﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;

using Db4objects.Db4o.Query;

using Db4o.Framework.Interfaces;
using Db4o.Framework.Exceptions;
using Db4o.Framework.Business;

namespace Db4o.Framework.Query
{
    internal class QueryFactory : ILogged
    {
        #region Design pattern : << Singleton QueryFactory >>

	    // read-only private member
        private static readonly QueryFactory instance = new QueryFactory();
        
	        // private construtor
        /// <summary>
        /// Private default constructor for singleton pattern
        /// </summary>
        private QueryFactory()
        {
        }

	        // public property
        public static QueryFactory Instance { get { return instance; } }

        #endregion

        /// <summary>
        /// Native Db4o query
        /// </summary>
        /// <typeparam name="T">ManagedType type</typeparam>
        /// <param name="e">delegate that represent native query</param>
        /// <returns></returns>
        public IList<T> NativeQuery<T>(System.Predicate<T> e) where T : ManagedType
        {
            logger.DebugFormat("[{0}] - Native Query - {1}", this.GetType().ToString(), e.Target.ToString());

            if (BusinessManager.Instance.BusinessAssembly != null)
            {
                return DataManager.Instance.Database.Query<T>(e);
            }
            else
            {
                ExceptionManager.Instance.ThrowWarnLogException("CoreInitializationException", "Error while retreiving object by value, Business assembly is null");
                return null;
            }
        }

        /// <summary>
        /// Retreive all stored object items of specified generic type 
        /// </summary>
        /// <typeparam name="T">Managed type you want in return</typeparam>
        /// <returns></returns>
        public IList<T> Retreive<T>() where T : ManagedType
        {
            try
            {
                logger.DebugFormat("[{0}] - Retreive query", this.GetType().ToString());

                if (BusinessManager.Instance.BusinessAssembly != null)
                    return DataManager.Instance.Database.Query<T>(typeof(T));
                else
                {
                    ExceptionManager.Instance.ThrowWarnLogException("CoreInitializationException", "Error while retreiving object by value, Business assembly is null");
                    return null;
                }
            }
            catch (DatabaseException e)
            {
                ExceptionManager.Instance.ThrowFatalLogException("DatabaseException", e.Source + ": " + e.Message);
                return null;
            }
        }

        #region RetreiveBy methods 
        /// <summary>
        /// Return the DbEntity specified by the id 
        /// </summary>
        /// <param name="Type">Type of DbEntity</param>
        /// <param name="value">unique object uuid </param>
        /// <returns></returns>
        public T RetreiveById<T>(long value) where T : ManagedType
        {
            try
            {
                IList<T> obj = RetreiveByValue<T>("Id", value);
                return obj[0];
            }
            catch (DatabaseException e)
            {
                ExceptionManager.Instance.ThrowWarnLogException("DatabaseException", "Error while retreiving object id " + value, e);
                return default(T);
            }


        }

        /// <summary>
        /// Retreive all objects of specified type wich match the value
        /// </summary>
        /// <param name="type">generic type</param>
        /// <param name="property">property to test</param>
        /// <param name="value">specified value</param>
        /// <typeparam name="T">list type</typeparam>
        /// <returns>list of specified generic type</returns>
        public IList<T> RetreiveByValue<T>(string property, object value) where T : ManagedType
        {
            if (BusinessManager.Instance.BusinessAssembly != null)
            {

                Type type = typeof(T);
                logger.DebugFormat("[{0}] - Retreive by value query", this.GetType().ToString());

                IList<T> list = DataManager.Instance.Database.Query<T>(delegate(T obj)
                    {
                        return obj.GetType().GetProperty(property).GetValue(obj, null).Equals(value);
                    }
                );
                return list;
            }
            else
            {
                ExceptionManager.Instance.ThrowWarnLogException("CoreInitializationException", "Error while retreiving object by value, Business assembly is null");
                return null;
            }
        }

        /// <summary>
        /// Retreive all objects of specified type wich match all the values
        /// </summary>
        /// <typeparam name="T">generic type</typeparam>
        /// <param name="values">properties and values hastable</param>
        /// <returns>list of specified generic type</returns>
        public IList<T> RetreiveByValue<T>(Hashtable values) where T : ManagedType
        {
            
            if (BusinessManager.Instance.BusinessAssembly != null)
            {
                Type type = typeof(T);
                logger.DebugFormat("[{0}] - Retreive query", this.GetType().ToString());

                IList<T> list = DataManager.Instance.Database.Query<T>(delegate(T obj)
                    {

                        bool match = false;

                        foreach (string key in values.Keys)
                            if (obj.GetType().GetProperty(key).GetValue(obj, null).Equals(values[key]))
                                match = true;
                            else
                                return false;

                        return match;
                    }
                );
                return list;
            }
            else
            {
                ExceptionManager.Instance.ThrowWarnLogException("CoreInitializationException", "Error while retreiving object by value, Business assembly is null");
                return null;
            }
        } 

        #endregion

        /// <summary>
        /// Convert IObjectSet Db4o type to generic list
        /// </summary>
        /// <typeparam name="T">generic type</typeparam>
        /// <param name="set">Db4o list</param>
        /// <returns>list of specified generic type</returns>
        //private IList<T> ConvertObjectSetToList<T>(Db4objects.Db4o.IObjectSet set)
        //{
        //    List<T> result = new List<T>();
        //    logger.DebugFormat("[ConvertToList] {0}", result.ToString());
        //    while (set.HasNext())
        //    {
        //        T obj = (T)set.Next();
        //        result.Add(obj);
        //    }
        //    return result;
        //}
      
    }
}
